在 Entity Framework Core(EF Core)中,Data Annotation(数据注解 / 数据特性) 是一种通过在实体类的属性或类上添加 [Attribute] 来配置模型映射的方式。虽然不如 Fluent API 灵活,但对于简单场景非常直观。
以下是 最常用的数据注解(Data Annotations) 及其作用说明:
📌 1. 表与架构配置
| 特性 | 作用 | 示例 |
|---|---|---|
[Table("TableName")] | 指定数据库表名 | [Table("Sys_User")] |
[Table("TableName", Schema = "dbo")] | 指定表名和数据库 Schema | [Table("Users", Schema = "auth")] |
📌 2. 主键与标识生成
| 特性 | 作用 | 示例 |
|---|---|---|
[Key] | 标记为主键(当属性名不是 Id 或 <ClassName>Id 时必需) | [Key] public int UserId { get; set; } |
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] | 数据库自动生成值(如自增) | [DatabaseGenerated(DatabaseGeneratedOption.Identity)] |
[DatabaseGenerated(DatabaseGeneratedOption.None)] | 值由程序提供(对应 .ValueGeneratedNever()) | [DatabaseGenerated(DatabaseGeneratedOption.None)] |
[DatabaseGenerated(DatabaseGeneratedOption.Computed)] | 值由数据库计算生成(如触发器、默认值函数) | — |
⚠️ 注意:
long Id+ 自增 → 用Identity;雪花 ID / 手动赋值 → 用None。
📌 3. 列配置
| 特性 | 作用 | 示例 |
|---|---|---|
[Column("ColumnName")] | 指定列名 | [Column("user_name")] |
[Column(TypeName = "varchar(50)")] | 指定数据库列类型 | [Column(TypeName = "nvarchar(100)")] |
[MaxLength(100)] | 设置最大长度(字符串/数组) | [MaxLength(255)] public string Name { get; set; } |
[StringLength(100)] | 同 MaxLength,但仅用于字符串 | [StringLength(50)] |
💡
MaxLength和StringLength都会生成数据库约束(如nvarchar(100)),也会在验证时生效(配合ModelState.IsValid)。
📌 4. 必填与非空约束
| 特性 | 作用 | 示例 |
|---|---|---|
[Required] | 表示该字段不可为 null(非空) | [Required] public string Email { get; set; } |
⚠️ 对 值类型(如
int,DateTime)无效,因为它们本身不能为 null。
若想让值类型可空且必填,请用int?+[Required]。
📌 5. 默认值(⚠️ EF Core 限制)
❗ 重要:EF Core 不支持通过 Data Annotation 设置数据库默认值!
必须使用 Fluent API 的.HasDefaultValue(...)。
但你可以用以下方式“模拟”应用层默认值:
csharp
public class User
{
[Required]
public bool IsActive { get; set; } = true; // C# 层默认值
}但这不会生成 SQL 的 DEFAULT (1),除非你在 Fluent API 中显式配置。
📌 6. 唯一约束(EF Core 5+)
| 特性 | 作用 | 示例 |
|---|---|---|
[Index(nameof(Email), IsUnique = true)] | 在类上定义唯一索引(EF Core 5+) | 见下方完整示例 |
csharp
[Index(nameof(Email), IsUnique = true)]
public class User
{
public int Id { get; set; }
public string Email { get; set; }
}⚠️ 注意:
[Index]是 类级别 特性,不是属性级别。
📌 7. 时间戳 / 并发控制
| 特性 | 作用 |
|---|---|
[Timestamp] | 标记为并发令牌(通常用于 byte[] 字段) |
csharp
[Timestamp]
public byte[] RowVersion { get; set; }等价于 Fluent API:.IsRowVersion()
📌 8. 忽略属性(不映射到数据库)
| 特性 | 作用 | 示例 |
|---|---|---|
[NotMapped] | 该属性不参与数据库映射 | [NotMapped] public string FullName => $"{FirstName} {LastName}"; |
📌 9. 外键关系(较少用,推荐 Fluent API)
| 特性 | 作用 |
|---|---|
[ForeignKey("PropertyName")] | 显式指定外键属性 |
[InverseProperty("PropertyName")] | 解决双向导航属性歧义 |
💡 实际开发中,复杂关系建议用 Fluent API 配置更清晰。
✅ 完整示例:UserEntity 使用 Data Annotations
csharp
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Table("Sys_User")]
[Index(nameof(Email), IsUnique = true)]
public class UserEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)] // 手动赋值 ID
[Column(TypeName = "bigint")]
public long Id { get; set; }
[Required, MaxLength(50)]
public string UserName { get; set; }
[Required, MaxLength(100)]
public string Email { get; set; }
[Column(TypeName = "bit")]
public bool IsActive { get; set; } = true;
[NotMapped]
public string DisplayName => $"User: {UserName}";
// 外键示例(可选)
public long DepartmentId { get; set; }
[ForeignKey("DepartmentId")]
public DepartmentEntity Department { get; set; }
}🔚 总结:常用 Data Annotations 速查表
| 功能 | 特性 |
|---|---|
| 表名 | [Table("...")] |
| 主键 | [Key] |
| 自增/手动ID | [DatabaseGenerated(...)] |
| 列名/类型 | [Column("...", TypeName = "...")] |
| 长度限制 | [MaxLength(n)] / [StringLength(n)] |
| 非空 | [Required] |
| 唯一索引 | [Index(..., IsUnique = true)](类上) |
| 不映射 | [NotMapped] |
| 并发控制 | [Timestamp] |
📝 最佳实践建议:
- 简单项目:可用 Data Annotations,代码直观;
- 中大型项目:推荐 Fluent API(
OnModelCreating),保持实体类干净,配置集中,功能更强; - 混合使用:可以同时用,但避免冲突(Fluent API 优先级更高)。
如有具体场景,我可以帮你选择更适合的方式!